<template>
  <div>
    <el-row :gutter="20">
      <el-col :span="9">
        <el-card shadow="hover">
          <div>
            <el-tabs v-model="activeAddress" type="card">
              <el-tab-pane label="生成地址" name="first">
                <div class="input-textarea">
                  <el-input type="textarea" :rows="19" v-model="textarea" :disabled="true">
                  </el-input>
                </div>
              </el-tab-pane>
            </el-tabs>
          </div>
        </el-card>
      </el-col>
      <el-col :span="15">
        <el-card shadow="hover">
          <div class="map-type">
            <el-tabs v-model="activeName" type="card">
              <el-tab-pane label="地图" name="first">
                <div class="map">
                  <div class="map-content">
                    <div id="container"></div>
                  </div>
                  <div class="map-button">
                    <div class="button-position">
                      <el-button type="danger" size="small" @click="clearMap">重置地图</el-button>
                    </div>
                    <div class="button-position">
                      <el-button type="success" size="small" @click="getAddress">获取当前地址</el-button>
                    </div>
                    <div class="button-position">
                      <el-button type="success" size="small" @click="routePlanning">路线规划</el-button>
                    </div>
                  </div>
                </div>
              </el-tab-pane>
            </el-tabs>
          </div>
        </el-card>
      </el-col>
    </el-row>
    <el-row :gutter="20">
      <el-col :span="9">
        <el-row style="margin-top: -20px;">
          <el-card class="box-card" shadow="hover">
            <template #header>
              <div class="card-header">
                <span>输入</span>
                <el-button type="primary" size="small" class="card-button" @click="getInput">获得地址矩阵</el-button>
              </div>
            </template>
            <el-input type="textarea" :rows="10" v-model="matrix" :disabled="true"> </el-input>
          </el-card>
        </el-row>
        <el-row>
          <el-card shadow="hover" style="width: 100%;height:170px">
            <div class="card-header">
              <el-tabs v-model="activeAlgorithm">
                <el-tab-pane label="蚁群算法" name="first">
                  <el-button type="primary" round size="small" @click="acoAlgorithm">
                    <span v-if="!loading1">蚁群算法计算</span>
                    <span v-else>计算中...</span>
                  </el-button>
                </el-tab-pane>
                <el-tab-pane label="模拟退火算法" name="second">
                  <el-button type="primary" round size="small" @click="saAlgorithm">
                    <span v-if="!loading2">模拟退火计算</span>
                    <span v-else>计算中...</span>
                  </el-button>
                </el-tab-pane>
                <el-tab-pane label="遗传算法" name="third">
                  <el-button type="primary" round size="small" @click="gaAlgorithm">
                    <span v-if="!loading3">遗传算法计算</span>
                    <span v-else>计算中...</span>
                  </el-button>
                </el-tab-pane>
                <el-tab-pane label="禁忌搜索算法" name="fourth">
                  <el-button type="primary" round size="small" @click="tabuAlgorithm">
                    <span v-if="!loading4">禁忌搜索算法计算</span>
                    <span v-else>计算中...</span>
                  </el-button>
                </el-tab-pane>
              </el-tabs>
            </div>
          </el-card>
        </el-row>
      </el-col>
      <el-col :span="15">
        <el-card shadow="hover" class="box-card">
          <div class="result-total">
            <el-tag>城市数: {{totalCity}}</el-tag>
            <el-tag>总距离: {{totalDistance}}</el-tag>
          </div>
          <el-tabs v-model="activeResult" type="card">
            <el-tab-pane label="表格展示" name="first">
              <el-table :data="tableData" border max-height="400">
                <el-table-column prop="number" label="城市编号" width="90">
                </el-table-column>
                <el-table-column prop="address" label="地址" width="450">
                </el-table-column>
                <el-table-column prop="distance" label="与下个城市之间的距离">
                </el-table-column>
              </el-table>
            </el-tab-pane>
            <el-tab-pane label="图展示" name="second">
              <canvas id="canvas" width="620" height="400"></canvas>
            </el-tab-pane>
          </el-tabs>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

<script>
var map;
var marker;
var geocoder;
var gpsArray = [];
var markers = [];
var ctx;
import AMap from "AMap"; // 引入高德原生AMap
import { ElMessage } from "element-plus";
import algorithm from "@/api/algorithm.js";

export default {
  data() {
    return {
      activeName: "first",
      activeAddress: "first",
      activeAlgorithm: "first",
      activeResult: "first",
      textarea: "",
      matrix: "",
      totalCity: 0,
      totalDistance: 0,
      tableData: [],
      loading1: false,
      loading2: false,
      loading3: false,
      loading4: false,
      nodes: [],
    };
  },
  mounted() {
    this.init();
  },
  methods: {
    //初始化
    init: function () {
      this.initMap();
      this.addPlugin();
      this.bindClickMap();
    },
    //初始化地图
    initMap: function () {
      map = new AMap.Map("container", {
        resizeEnable: true,
        zoom: 13,
      });
    },
    //异步同时加载多个插件
    addPlugin: function () {
      AMap.plugin(
        ["AMap.ToolBar", "AMap.Scale", "AMap.Geocoder", "AMap.Driving"],
        function () {
          map.addControl(new AMap.ToolBar());
          map.addControl(new AMap.Scale());
          map.addControl(new AMap.Geocoder());
          map.addControl(new AMap.Driving());
        }
      );
    },
    // 绑定地图点击事件
    bindClickMap: function () {
      map.on("click", this.clickHandler);
    },
    // 添加标记点
    clickHandler: function (e) {
      var gps = [e.lnglat.getLng(), e.lnglat.getLat()]; //获得经纬度
      marker = new AMap.Marker({
        position: gps, // 坐标
        //标记
        content:
          '<div style="width:19px;height: 31px; color:white; text-align: center;line-height: 21px;background: url(' +
          "'" +
          "https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png" +
          "'" +
          ');}">' +
          gpsArray.length +
          "</div>",
      });
      gpsArray.push(gps); //获得经纬度数组
      markers.push(marker); //标记点数组
      map.add(marker); // 将创建的点标记添加到已有的地图实例
    },
    //重置地图
    clearMap: function () {
      map.remove(markers);
      gpsArray = [];
      markers = [];
      this.init();
      this.textarea = "";
      this.matrix = "";
    },
    //获取地址
    getAddress: function () {
      this.textarea = "";
      var that = this;
      if (!geocoder) {
        geocoder = new AMap.Geocoder({
          city: "010", //城市设为北京，默认：“全国”
          radius: 500, //范围，默认：500
          batch: true,
        });
      }
      var temp = gpsArray.concat();
      //高德地图api只允许一次性提交20个地址,这里循环获取所有的地址
      while (temp.length > 0) {
        geocoder.getAddress(temp, function (status, result) {
          if (status === "complete" && result.info === "OK") {
            var str = "";
            for (var i = 0; i < result.regeocodes.length; i += 1) {
              str = str + result.regeocodes[i].formattedAddress + "\n";
            }
          }
          that.textarea = that.textarea + str;
        });
        temp.splice(0, 20);
      }
    },
    //规划驾车路线
    routePlanning: function () {
      this.initMap();
      this.addPlugin();
      var points = [];
      for (var i = 0; i < this.tableData.length; i++) {
        var str = "{ keyword: '" + this.tableData[i].address + "'}";
        var obj = eval("(" + str + ")");
        points.push(obj);
      }
      var driving;
      driving = new AMap.Driving({
        policy: AMap.DrivingPolicy.LEAST_TIME,
        map: map,
      });
      driving.search(points, function (status, result) {
        if (status === "complete") {
          console.log("绘制驾车路线完成");
        } else {
          console.log("获取驾车数据失败：" + result);
        }
      });
    },
    //获得算法输入信息
    getInput: function () {
      this.matrix = "";
      this.getMatrix();
    },
    //获得距离矩阵
    getMatrix: function () {
      var dis = "";
      for (var i = 0; i < gpsArray.length; i++) {
        for (var j = 0; j < gpsArray.length; j++) {
          if (j === gpsArray.length - 1) {
            dis =
              dis +
              Math.round(AMap.GeometryUtil.distance(gpsArray[i], gpsArray[j])) +
              "\n";
          } else {
            dis =
              dis +
              Math.round(AMap.GeometryUtil.distance(gpsArray[i], gpsArray[j])) +
              " ";
          }
        }
      }
      this.matrix = gpsArray.length + "\n" + dis;
    },
    acoAlgorithm: function () {
      if (this.textarea != "" && this.matrix != "") {
        this.loading1 = true;
        algorithm
          .acoAlgorithm(this.matrix, this.textarea)
          .then((response) => {
            this.loading1 = false;
            this.alertMessage("计算完毕", "success");
            this.tableData = response.data;
            this.totalCity = response.data[0].totalCity;
            this.totalDistance = response.data[0].totalDistance;
            this.drawGraph();
          })
          .catch(() => {
            this.loading1 = false;
          });
      } else {
        this.alertMessage("请填写相关输入信息", "warning");
      }
    },
    saAlgorithm: function () {
      if (this.textarea != "" && this.matrix != "") {
        this.loading2 = true;
        algorithm
          .saAlgorithm(this.matrix, this.textarea)
          .then((response) => {
            this.loading2 = false;
            this.alertMessage("计算完毕", "success");
            this.tableData = response.data;
            this.totalCity = response.data[0].totalCity;
            this.totalDistance = response.data[0].totalDistance;
            this.drawGraph();
          })
          .catch(() => {
            this.loading2 = false;
          });
      } else {
        this.alertMessage("请填写相关输入信息", "warning");
      }
    },
    gaAlgorithm: function () {
      if (this.textarea != "" && this.matrix != "") {
        this.loading3 = true;
        algorithm
          .gaAlgorithm(this.matrix, this.textarea)
          .then((response) => {
            this.loading3 = false;
            this.alertMessage("计算完毕", "success");
            this.tableData = response.data;
            this.totalCity = response.data[0].totalCity;
            this.totalDistance = response.data[0].totalDistance;
            this.drawGraph();
          })
          .catch(() => {
            this.loading3 = false;
          });
      } else {
        this.alertMessage("请填写相关输入信息", "warning");
      }
    },
    tabuAlgorithm: function () {
      if (this.textarea != "" && this.matrix != "") {
        this.loading4 = true;
        algorithm
          .tabuAlgorithm(this.matrix, this.textarea)
          .then((response) => {
            this.loading4 = false;
            this.alertMessage("计算完毕", "success");
            this.tableData = response.data;
            this.totalCity = response.data[0].totalCity;
            this.totalDistance = response.data[0].totalDistance;
            this.drawGraph();
          })
          .catch(() => {
            this.loading4 = false;
          });
      } else {
        this.alertMessage("请填写相关输入信息", "warning");
      }
    },
    drawGraph: function () {
      this.computePoint();
      this.drawPoint();
      this.connect();
    },
    computePoint: function () {
      for (var i = 0; i < gpsArray.length; i++) {
        var pixel = map.lngLatToContainer(gpsArray[i]); // 获得 Pixel 对象
        this.nodes[i] = pixel;
        this.nodes[i].x = this.nodes[i].x.toFixed(1);
        this.nodes[i].y = this.nodes[i].y.toFixed(1);
      }
    },
    drawPoint: function () {
      var canvas = document.getElementById("canvas");
      ctx = canvas.getContext("2d");
      ctx.clearRect(0, 0, 620, 400);
      for (var i = 0; i < this.nodes.length; i++) {
        ctx.beginPath();
        if (0 === i) {
          ctx.strokeStyle = "#FF0000";
          ctx.fillStyle = "#FF0000";
          ctx.font = "15px Arial";
          ctx.fillText("起点", this.nodes[i].x, this.nodes[i].y);
          ctx.arc(this.nodes[i].x, this.nodes[i].y, 3, 0, 2 * Math.PI);
          ctx.fill();
          ctx.stroke();
        } else {
          ctx.strokeStyle = "#000000";
          ctx.fillStyle = "#000000";
          ctx.font = "15px Arial";
          ctx.fillText("N" + i, this.nodes[i].x, this.nodes[i].y);
          ctx.arc(this.nodes[i].x, this.nodes[i].y, 3, 0, 2 * Math.PI);
          ctx.fill();
          ctx.stroke();
        }
      }
    },
    connect: function () {
      for (var i = 1; i < this.tableData.length; i++) {
        ctx.beginPath();
        var r1 = Math.floor(Math.random() * 255);
        var r2 = Math.floor(Math.random() * 255);
        var r3 = Math.floor(Math.random() * 255);
        ctx.strokeStyle = "rgba(" + r1 + "," + r2 + "," + r3 + ")"; //线颜色
        var x1 = this.nodes[this.tableData[i - 1].number].x;
        var y1 = this.nodes[this.tableData[i - 1].number].y;
        ctx.moveTo(x1, y1); //移动到起始点位置
        var x2 = this.nodes[this.tableData[i].number].x;
        var y2 = this.nodes[this.tableData[i].number].y;
        ctx.lineTo(x2, y2); //移动到停止位置
        ctx.stroke();
      }
    },
    alertMessage: function (msg, type) {
      ElMessage({
        message: msg,
        type: type,
      });
    },
  },
};
</script>
<style scope>
.el-row {
  padding-top: 20px;
}
.map {
  margin-top: 5px;
  display: flex;
  flex-direction: row;
}
.map-content {
  float: left;
  width: 620px;
  height: 400px;
}
.map-button {
  float: left;
}
#container {
  width: 100%;
  height: 100%;
}
.button-position {
  margin-top: 10px;
  margin-left: 10px;
}
.card-button {
  float: right;
}
.box-card {
  width: 100%;
  height: 100%;
}
.result-total {
  float: right;
}
.el-tag {
  margin-left: 20px;
}
.el-table {
  width: 100%;
}
#canvas {
  width: 620px;
  height: 400px;
}
</style>